#!/usr/bin/env python
# encoding: utf-8
"""
...
"""

#
#  Copyright (c) 2009 University of Dundee. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions
#  are met:
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#  SUCH DAMAGE.

import unittest
import sys

from StringIO import StringIO
from getopt import getopt, GetoptError
from copy import deepcopy

# We're using lxml's ElementTree implementation for XML manipulation due to
# its XSLT integration.
from lxml.etree import XML, XSLT, Element, SubElement, ElementTree, dump, parse

# Handle Python 2.5 built-in ElementTree
#try:
#        from xml.etree.ElementTree import XML, Element, SubElement, ElementTree, dump
#except ImportError:
#        from elementtree.ElementTree import XML, Element, SubElement, ElementTree, dump


def usage(error):
    """Prints usage so that we don't have to. :)"""
    cmd = sys.argv[0]
    print """%s
Usage: %s <stylesheet.xsl> <input.xml> [output.xml]
Runs the stylesheet transform upon an XML instance document.

Options:

Examples:
  %s foo.xslt bar.xml bar_new.xml

Report bugs to ome-devel@lists.openmicroscopy.org.uk""" % (error, cmd, cmd)
    sys.exit(2)

def run_stylesheet(xslt, document):
    xslt_doc = parse(xslt)
    transform = XSLT(xslt_doc)
    return transform(document)






class Test200809(unittest.TestCase):
    STYLESHEET = "../specification/Xslt/2008-09-to-2009-09.xsl"

    DOCUMENT = "../specification/InProgress/test-ome-samples/sample-2008-09.ome"

    OLD_OME_NS = "http://www.openmicroscopy.org/Schemas/OME/2008-09"

    OLD_SPW_NS = "http://www.openmicroscopy.org/Schemas/SPW/2008-09"

    NEW_OME_NS = "http://www.openmicroscopy.org/Schemas/OME/2009-09"

    NEW_SPW_NS = "http://www.openmicroscopy.org/Schemas/SPW/2009-09"

    # Create the XPath for the element in the scope of root or local.
    # and add attribute if supplied.
    def createXPath(self, scope, NS, elementName, attribute=None):
        if(scope=='local'):
            scope = './';
        if(scope=='root'):
            scope = './/';
        if(scope=='all'):
             return '%s[@%s]' % (elementName, attribute)
        if(attribute!=None):
            return '%s{%s}%s[@%s]' % (scope, NS, elementName, attribute)
        return '%s{%s}%s' % (scope, NS, elementName);

    # return the name of the element without NameSpace e.g. {NameSpace}elementName.
    def localName(self, elementTag):
        return elementTag[elementTag.find("}") + 1:]

    # if var is not none then remove trailing spaces and if '' then return None.
    def stripStr(self, var):
        if(var != None):
            if(var.strip()!=''):
                return var.strip();
        return None;

    # Get all elements from rootElement in elementList in namespace NS.
    def getAllElements(self, rootElement, NS, elementList):
        returnList = [];
        for elementName in elementList:
            elementXPath = self.createXPath('root', NS, elementName);
            foundElements = rootElement.findall(elementXPath);
            returnList.extend(foundElements);
        return returnList;

    # Check that the elements in the exclusionList are not in the element.
    def checkElementsExcluded(self, element, exclusionList):
        children = element.getchildren();
        for child in children:
            self.assertFalse(child in exclusionList)

    # Check that the attributes in element with Namespace NS are not in exclusionList.
    def checkAttributesExcluded(self, root, NS, element, exclusionList):
        for attribute in exclusionList:
            xpath = self.createXPath('all',NS, element, attribute);
            self.assertTrue(len(root.findall(xpath))==0)

    # Check the alll the elements in oldRoot with namespace oldNS have been mapped to newRoot with namespace newNS.
    # Rename those elements in renameMap.
    def checkElementsMapped(self, oldRoot, oldNS, newRoot, newNS, renameMap):
        for mappedElement in renameMap:
            oldXPath = self.createXPath('root',oldNS, mappedElement);
            newXPath = self.createXPath('root',newNS, renameMap[mappedElement]);
            oldElements = oldRoot.findall(oldXPath);
            newElements = newRoot.findall(newXPath);
            self.assertEqual(len(oldElements),len(newElements))
            self.assertTrue(len(newRoot.findall(oldXPath))==0)

    # Check the alll the elements in oldRoot with namespace oldNS have been mapped to newRoot with namespace newNS.
    # Rename those elements in renameMap.
    def checkElementsMappedNoCount(self, oldRoot, oldNS, newRoot, newNS, renameMap):
        for mappedElement in renameMap:
            oldXPath = self.createXPath('root',oldNS, mappedElement);
            newXPath = self.createXPath('root',newNS, renameMap[mappedElement]);
            oldElements = oldRoot.findall(oldXPath);
            newElements = newRoot.findall(newXPath);
            self.assertTrue(len(newRoot.findall(oldXPath))==0)

    # Compare Elements in oldElement with the NameSpace oldElementNS to the attributes with the same name in newElement.
    # Don't compare those elements in the exceptionList.
    # Rename those attributes in the renameMap.
    def compareElementsWithAttributes(self, oldElement, oldElementNS, newElement, exceptionList=None, renameMap=None):
        for oldChildElement in oldElement.getchildren():
            elementName = self.localName(oldChildElement.tag);
            if(exceptionList != None):
                if(elementName in exceptionList):
                    continue;
            mappedName = elementName;
            if(renameMap != None):
                if(elementName in renameMap):
                    mappedName = renameMap[mappedName];
            newValue = newElement.get(mappedName);
            self.assertFalse(newValue==None);
            self.assertEquals(newValue, self.stripStr(oldChildElement.text));

    # Compare Elements in left with the attributes in right if they are in comparison map.
    def compareElementsWithAttributesFromMap(self, left, right, comparisonMap):
        for leftChild in left.getchildren():
            leftChildName = self.localName(leftChild.tag);
            if(leftChildName not in comparisonMap):
                continue;
            mappedName = comparisonMap[leftChildName];
            newValue = newElement.get(mappedName);
            self.assertFalse(newValue==None);
            self.assertEquals(newValue, self.stripStr(leftChild.text));

    # Check that the element contains the elements in containsList
    def containsElements(self, element, NS, containsList):
        containsMap = {};
        for name in containsList:
            containsMap[name] = False;
        for child in element.getchildren():
            elementName = self.localName(child.tag);
            if(elementName in containsMap):
                containsMap[elementName] = True;
        for key in containsMap:
            self.assertEquals(containsMap[key], True);

    # Check that the element contains the elements in containsMap with the values in the map
    def containsElementsWithValues(self, element, NS, containsMap):
        equalsMap = {};
        for key in containsMap:
            equalsMap[key] = False;
        for child in element.getchildren():
            elementName = self.localName(child.tag);
            if(elementName in containsMap):
                if(containsMap[elementName] == self.stripStr(child.text)):
                    equalsMap[elementName] = True;
        for key in equalsMap:
            self.assertEquals(equalsMap[key], True);


    # Check that the element contains the attributes in containsList
    def containsAttributes(self, element, containsList):
        containsMap = {};
        for name in containsList:
            containsMap[name] = False;
        for attribute in element.attrib.keys():
            if(attribute in containsMap):
                containsMap[attribute] = True;
        for key in containsMap:
            self.assertEquals(containsMap[key], True);

    # Check that the element contains the attributes in containsMap and the values in the map match the values in the element.
    def containsAttributesWithValues(self, element, containsMap):
        equalsMap = {};
        for key in containsMap:
            equalsMap[key] = False;
        for attribute in element.attrib.keys():
            if(attribute in containsMap):
                if(containsMap[attribute] == element.get(attribute)):
                    equalsMap[attribute] = True;
        for key in equalsMap:
            self.assertEquals(equalsMap[key], True);

    # Get elements in list as a map from element [name:value], removing namespace.
    def getElementsAsMap(self, element):
        childMap = {};
        for child in element.getchildren():
            childMap[self.localname(child.tag)] = child.text;
        return childMap;

   # Get attributes in list as a map from element [name:value].
    def getElementsAsMap(self, element):
        attributeMap = {};
        for attribute in element.attrib.keys():
            attributeMap[attribute] = element.get(attribute);
        return attributeMap;

    # Compare elements from oldElement in oldElement NameSpace to the newElement in newElement NameSpace.
    # Don't compare those elements in the exceptionList list.
    # Rename those elements in the renameMap.
    def compareElements(self, oldElement, oldElementNS, newElement, newElementNS, exceptionList=None, renameMap=None, inclusionList = None):
        inclusionMap = {};
        if(inclusionList != None):
            for elem in inclusionList:
                inclusionMap[elem] = False;
        for oldChildElement in oldElement.getchildren():
            elementName = self.localName(oldChildElement.tag);
            if(exceptionList != None):
                if(elementName in exceptionList):
                    continue;
            mappedName = elementName;
            if(renameMap != None):
                if(elementName in renameMap):
                    mappedName = renameMap[elementName];
            if(elementName in inclusionMap):
                inclusionMap[elementName] = True;
            newChildXPath = self.createXPath('local', newElementNS, mappedName);
            newChildElement = newElement.find(newChildXPath);
            self.assertFalse(newChildElement, None);
            self.assertEquals(self.stripStr(newChildElement.text), self.stripStr(oldChildElement.text))
        for key in inclusionMap:
            self.assertEquals(inclusionMap[key], True);

    # Compare attributes from oldElement to new element
    # Don't compare those elements in the exceptionList.
    # Rename those elements in the renameMap.
    def compareAttributes(self, oldElement, newElement, exceptionList=None, renameMap=None):
        for key in oldElement.attrib.keys():
            if(exceptionList != None):
                print key
                if(key in exceptionList):
                    continue;
            mappedKey = key;
            if(renameMap != None):
                if(key in renameMap):
                    mappedKey = renameMap[key];
            newValue = newElement.get(mappedKey);
            oldValue = oldElement.get(key);
            if(oldValue != newValue):
                print 'FAILURE'
                print 'EXCEPTIONLIST %s' % exceptionList
                print 'oldElement.tag %s' % oldElement.tag
                print 'newElement.tag %s' % newElement.tag
                print key
                print oldValue
                print newValue
                print 'END FAILURE'
            self.assertEquals(newValue, oldValue);

    # Get all the child elements from the element, in namespace.
    # Exclude thoses child elements in the exclusions list.
    def getChildElements(self, element, elementNS, exceptionList):
        childList = [];
        for child in element.getchildren():
            name = self.localName(child.tag);
            if(name not in exceptionList):
                childList.append(name);
        return childList;

    # Return true if the attributes in the elements left and right match and the number if children match.
    def elementsEqual(self, left, right, renamedAttributes):
        if(self.localName(tag)!=self.localName(right.tag)):
            return false;
        if(len(left) != len(right)):
            return False;
        if(len(left.getchildren()) != len(right.getchildren())):
            return false;
        for leftAttribute in left:
            if(renamedAttributes[leftAttribute] not in right):
                return false;
            if(left[leftAttribute] != right[renamedAttributes[leftAttribute]]):
                return false;
        return True;

    # Select the element in rightList who's attributes match the element left.
    def getElementFromList(self, left, rightList, renamedAttributes):
        for right in rightList:
            if(elementsEqual(left, right, renamedAttributes, renamedElements)):
                return right;
        return None;

    # Compare graph's are same, the attributes and elements maybe renamed using the renameAttributes
    # and renameElements map, this method assumes that the graphs are in the same element order.
    def compareGraphs(self, left, right, ignoreAttributes = None, renameAttributes = None, renameElements=None):
        print 'IGNOREATTRIBUTES %s' % ignoreAttributes
        leftChildren = left.getchildren();
        rightChildren = right.getchildren();
        self.assertEqual(len(leftChildren), len(rightChildren));
        if(len(leftChildren)==0):
            return;
        for i in range(len(leftChildren)):
            self.compareAttributes(leftChildren[i], rightChildren[i], ignoreAttributes, renameAttributes);
            if(renameElements==None):
                self.assertEqual(self.localName(leftChildren[i].tag), self.localName(rightChildren[i].tag));
            else:
                leftChildTag = self.localName(leftChildren[i].tag);
                if(leftChildTag in renameElements):
                    leftChildTag = renameElements[leftChildTag];
                self.assertEqual(leftChildTag, self.localName(rightChildren[i].tag));
            self.assertEqual(self.stripStr(leftChildren[i].text), self.stripStr(rightChildren[i].text));
            self.compareGraphs(leftChildren[i], rightChildren[i], ignoreAttributes, renameAttributes, renameElements);

    # Compare graph's are same, the attributes and elements maybe renamed using the renameAttributes
    # and renameElements map, this method assumes that the graphs are in the same element order.
    def compareGraphsWithoutOrder(self, left, right, renameAttributes = None, renameElements=None):
        leftChildren = left.getchildren();
        rightChildren = right.getchildren();
        self.assertEqual(len(leftChildren), len(rightChildren));
        if(len(leftChildren)==0):
            return;
        for i in range(len(leftChildren)):
            rightChild = self.getElementFromList(leftChildren[i], rightChildren, renameAttributes);
            self.assertTrue(rightChild!=None);
            if(renameElements==None):
                self.assertEqual(self.localName(leftChildren[i].tag), self.localName(rightChild.tag));
            else:
                self.assertEqual(renameElements[self.localName(leftChildren[i].tag)], self.localName(rightChild.tag));
            self.assertEqual(self.stripStr(leftChildren[i].text), self.stripStr(rightChild.text));
            self.compareGraphsWithoutOrder(leftChildren[i], rightChild, ignoreAttributes, renameAttributes, renameElements);

    # get the name of a reference, by removing the Ref suffix.
    def elementRefName(self, name):
        return name[:len(name)-3];

    # return true if the element is a reference, has Ref suffix.
    def isRef(self, element):
        return (element.tag[len(element.tag)-3:]=='Ref');

    # return the elemenet in the root tree with name element name and id
    # if it does not exist it will return None
    def findElementByID(self, root, NS, elementName, id):
        elements = self.getAllElements(root, NS, [elementName]);
        for element in elements:
            if(element.get('ID')==id):
                return element;
        return None;

    # create a new element based on the element param, this will copy the element tag,
    # and attribs but not children. To copy children use deepcopy.
    def shallowcopy(self, element):
        newElement = Element(element.tag);
        newElement.text = element.text
        for key in element.keys():
            newElement.set(key, element.get(key));
        return newElement;

    # Replace the references in elemenet with the full element from root, this method only works
    # on the children of the element, to replace all references in element use replaceRefsWithElementRecurse.
    # If RefList is not empty it will only replace the References in RefList.
    # The elements in RefList should only be the name of the element, ROI not ROIRef.
    def replaceRefsWithElements(self, root, NS, element, RefList=None):
        if(RefList==None):
            RefList = [];
        newElement = self.shallowcopy(element);
        children = element.getchildren();
        if(len(children)==0):
            return;
        for i, child in enumerate(children):
            elementName = self.elementRefName(self.localName(child.tag))
            print elementName
            if(self.isRef(child) and elementName in RefList):
                elementFromRef = self.findElementByID(root, NS, elementName, child.get('ID'));
                newElement.append(deepcopy(elementFromRef));
            else:
                newElement.append(deepcopy(child));
        return newElement

    # Replace the references in elemenet with the full element from root, this method works to
    # replace all references in element.
    # If RefList is not empty it will only replace the References in RefList.
    # The elements in RefList should only be the name of the element, ROI not ROIRef.
    def replaceRefsWithElementsRecurse(self, root, NS, element, RefList=None):
        if(RefList==None):
            RefList = [];
        newElement = self.shallowcopy(element);
        children = element.getchildren();
        if(len(children)==0):
            return newElement;
        for i, child in enumerate(children):
            elementName = self.elementRefName(self.localName(child.tag))
            if(self.isRef(child) and elementName in RefList):
                elementFromRef = self.findElementByID(root, NS, elementName, child.get('ID'));
                newElement.append(deepcopy(elementFromRef));
            else:
                newElement.append(self.replaceRefsWithElementsRecurse(root, NS, child, RefList));
        return newElement

    # Move the child elements from removeElement to removeElements parent element and remove
    # it from the element.
    def moveElementsFromChildToParent(self, element, NS, removeElement):
        returnElement = deepcopy(element);

        xpath = self.createXPath('root', NS, removeElement);
        elementsToRemove = returnElement.findall(xpath);
        for elementToRemove in elementsToRemove:
            elementsParent = elementToRemove.getparent();
            elementsParent.remove(elementToRemove);
            for child in elementToRemove.getchildren():
                elementsParent.append(child);
        return returnElement;


    def setUp(self):
        self.xslt_file = open(self.STYLESHEET)
        self.instance_file = open(self.DOCUMENT)
        self.instance_document = parse(self.instance_file)
        self.result = run_stylesheet(self.xslt_file, self.instance_document)
        self.old_root = self.instance_document.getroot()
        self.new_root = self.result.getroot()

    def tearDown(self):
        self.xslt_file.close()
        self.instance_file.close()

    def test_objective_settings(self):
        """
        ObjectiveRef to ObjectiveSettings transformation
        """

        self.checkElementsMappedNoCount( self.old_root, self.OLD_OME_NS, self.new_root, self.NEW_OME_NS,{'ObjectiveRef':'ObjectiveSettings'})

    def test_light_source_settings(self):
        """
        LightSourceRef to LightSettings transformation
        """
        self.checkElementsMappedNoCount(self.old_root, self.OLD_OME_NS, self.new_root, self.NEW_OME_NS, {'LightSourceRef':'LightSourceSettings'})

    def test_detector_settings(self):
        """
        DetectorRef to DetectorSettings transformation
        """
        self.checkElementsMappedNoCount(self.old_root, self.OLD_OME_NS, self.new_root, self.NEW_OME_NS, {'DetectorRef':'DetectorSettings'})

    def test_wellsample_attributes(self):
        """
        Change the WellSample attributes
        Remove Index, Rename PosX to PositionX & PosY to PositionY
        """

        self.checkElementsMapped(self.old_root, self.OLD_SPW_NS, self.new_root, self.NEW_SPW_NS, {'WellSample':'WellSample'})
        self.checkAttributesExcluded(self.new_root, self.NEW_SPW_NS, 'WellSample', ['Index'])
        self.checkAttributesExcluded(self.new_root, self.NEW_SPW_NS, 'WellSample', ['PosX'])
        self.checkAttributesExcluded(self.new_root, self.NEW_SPW_NS, 'WellSample', ['PosY'])

        # count old PosX and PosY attributes in old WellSample
        xpath = './/{%s}WellSample' % self.OLD_SPW_NS
        old_elements = self.old_root.findall(xpath)
        reference_count_posx = 0
        reference_count_posy = 0
        for element in old_elements:
            if ('PosX' in element.keys()):
                reference_count_posx+=1
            if ('PosY' in element.keys()):
                reference_count_posy+=1

        # count old PosX and PosY attributes in new WellSample
        xpath = './/{%s}WellSample' % self.NEW_SPW_NS
        new_wellsample_elements = self.new_root.findall(xpath)
        new_count_posx = 0
        new_count_posy = 0
        for element in new_wellsample_elements:
            if ('PositionX' in element.keys()):
                new_count_posx+=1
            if ('PositionY' in element.keys()):
                new_count_posy+=1

        # compare old PosX attributes to new PositionX attributes
        self.assertEquals(reference_count_posx, new_count_posx)
        # compare old PosY attributes to new PositionY attributes
        self.assertEquals(reference_count_posy, new_count_posy)

    def test_description_no_lang(self):
        """
        Change OME:Description to be a local simple type in each
        element it is used called Description based on xsd:string
        """
        print self.result
        # find old OME:Description
        xpath = './/{%s}Description' % self.OLD_OME_NS
        reference_count_all = len(self.old_root.findall(xpath))
        self.assertTrue(reference_count_all > 0)
        # find old OME:Description only in SPW:Screen
        xpath = './/{%s}Screen/{%s}Description' % (self.OLD_SPW_NS, self.OLD_OME_NS)
        reference_screen_descripton_elements = self.old_root.findall(xpath)
        # find new OME:Description
        xpath = './/{%s}Description' % self.NEW_OME_NS
        new_ome_descripton_elements = self.new_root.findall(xpath)
        # find new SPW:Description only in SPW:Screen
        xpath = './/{%s}Screen/{%s}Description' % (self.NEW_SPW_NS, self.NEW_SPW_NS)
        new_screen_descripton_elements = self.new_root.findall(xpath)
        # old attributes must not be present in new OME:Description nodes
        xpath = './/{%s}Description' % self.NEW_OME_NS
        new_elements = self.new_root.findall(xpath)
        for element in new_elements:
            self.assertFalse('lang' in element.keys())
        # old attributes must not be present in new SPW:Description nodes
        xpath = './/{%s}Description' % self.NEW_SPW_NS
        new_elements = self.new_root.findall(xpath)
        for element in new_elements:
            self.assertFalse('lang' in element.keys())
        # all old OME must equal new OME + new SPW
        self.assertEquals(reference_count_all, len(new_ome_descripton_elements)+len(new_screen_descripton_elements))
        # old OME in screen must equal new OME in screen
        self.assertEquals(len(reference_screen_descripton_elements),len(new_screen_descripton_elements))

    def test_plate_description(self):
        """
        Change the Description attribute to be a local simple type in the Plate
        element to be a Description element based on xsd:string
        """
        # find old SPW:Plate
        xpath = './/{%s}Plate' % self.OLD_SPW_NS
        reference_count_all = len(self.old_root.findall(xpath))
        self.assertTrue(reference_count_all > 0)
        # count old Description attributes in Plate
        old_elements = self.old_root.findall(xpath)
        reference_count_attribute = 0
        for element in old_elements:
            if ('Description' in element.keys()):
                reference_count_attribute+=1

        # find new SPW:Plate
        xpath = './/{%s}Plate' % self.NEW_SPW_NS
        new_plate_count = len(self.new_root.findall(xpath))
        # old plate equals new plate
        self.assertEquals(reference_count_all, new_plate_count)
        # find new SPW:Description only in SPW:Plate
        xpath = './/{%s}Plate/{%s}Description' % (self.NEW_SPW_NS, self.NEW_SPW_NS)
        new_plate_descripton_count = len(self.new_root.findall(xpath))
        # compare old Description attributes to new Description elements in Plate
        self.assertEquals(reference_count_attribute, new_plate_descripton_count)

        # old attributes must not be present in new SPW:Plate nodes
        xpath = './/{%s}Plate' % self.NEW_SPW_NS
        new_elements = self.new_root.findall(xpath)
        for element in new_elements:
            self.assertFalse('Description' in element.keys())

    def test_dataset_no_locked(self):
        """
        Remove Locked from Dataset
        """
        self.checkElementsMapped(self.old_root, self.OLD_OME_NS, self.new_root, self.NEW_OME_NS, {'Dataset':'Dataset'})
        self.checkAttributesExcluded(self.new_root, self.NEW_OME_NS, 'Dataset', ['Locked'])

    def test_objective_elements_to_attributes(self):
        """
        Objective transformation. See stylesheet for details
        """
        """
        fromElements = self.getAllElements(self.old_root, self.OLD_OME_NS, ['Objective']);

        toAttributes = self.getAllElements(self.new_root, self.NEW_OME_NS, ['Objective']);
        for i, toAttributeElement in enumerate(toAttributes):
            self.compareElementsWithAttributes(fromElements[i], self.OLD_OME_NS, toAttributeElement);
        """

    def test_experimenter_elements_to_attributes(self):
        """
        Experimenter transformation. See stylesheet for details
        """

        fromElements = self.getAllElements(self.old_root, self.OLD_OME_NS, ['Experimenter']);
        toAttributes = self.getAllElements(self.new_root, self.NEW_OME_NS, ['Experimenter']);
        self.assertEqual(len(fromElements), len(toAttributes));
        if (len(fromElements) == 0):
            return;
        inverseExceptionList = self.getChildElements(fromElements[0], self.OLD_OME_NS, ['GroupRef']);
        for i, toAttributeElement in enumerate(toAttributes):
            self.compareElementsWithAttributes(fromElements[i], self.OLD_OME_NS, toAttributeElement, ['GroupRef'], {'OMEName':'UserName'});
            self.compareElements(fromElements[i], self.OLD_OME_NS, toAttributeElement, self.NEW_OME_NS, inverseExceptionList)

    def test_filter_set_elements_to_attributes(self):
        """
        FilterSet transformation. See stylesheet for details
        """
        fromAttributes = self.getAllElements(self.old_root, self.OLD_OME_NS, ['FilterSet'])
        toElements = self.getAllElements(self.new_root, self.NEW_OME_NS, ['FilterSet'])
        self.assertEqual(len(fromAttributes), len(toElements))
        if(len(fromAttributes)==0):
            return;
        for i, fromAttributeElement in enumerate(fromAttributes):
            self.compareElementsWithAttributesFromMap(toElements[i], fromAttributeElement, {'EmFilterRef':'EmissionFilterRef', 'ExFilterRef':'ExcitationFilterRef'})
            self.compareAttributes(fromAttributeElement, toElements[i], ["EmFilterRef","ExFilterRef","DichroicRef"])
        self.checkAttributesExcluded(self.new_root, self.NEW_OME_NS, 'FilterSet', ["EmFilterRef","ExFilterRef","DichroicRef"])

    def test_tiffdata_rename_numplanes_to_planecount(self):
        """
        TiffData transformation. See stylesheet for details
        """
        oldElements = self.getAllElements(self.old_root, self.OLD_OME_NS, ['TiffData']);
        newElements = self.getAllElements(self.new_root, self.NEW_OME_NS, ['TiffData']);

        for i, oldElement in enumerate(oldElements):
            self.compareAttributes(oldElement, newElements[i], None, {"NumPlanes":"PlaneCount"});

    def test_experiment_copy_microbeammanipulation_from_image(self):
        """
        Experiment transformation. See stylesheet for details
        """
        oldElements = self.getAllElements(self.old_root, self.OLD_OME_NS, ["Experiment"]);
        newElements = self.getAllElements(self.new_root, self.NEW_OME_NS, ["Experiment"]);


        for i, newElement in enumerate(newElements):
            id = newElement.get('ID');
            elementWithRefs = self.findElementByID(self.old_root,self.OLD_OME_NS,'Experiment',id);
            oldElementWithoutMBRef = self.replaceRefsWithElements(self.old_root, self.OLD_OME_NS, elementWithRefs, ["MicrobeamManipulation"]);
            oldElementsWithoutROIRef = self.replaceRefsWithElementsRecurse(self.old_root, self.OLD_OME_NS, oldElementWithoutMBRef, ["ROI"]);
            oldElementWithoutChannel = self.moveElementsFromChildToParent(oldElementsWithoutROIRef, self.OLD_OME_NS, "Channels");
            print 'DUMP(oldElementWithoutChannel)';
            dump(oldElementWithoutChannel);
            print 'DUMP(newElement)';
            dump(newElement);
            self.compareGraphs(oldElementWithoutChannel, newElement, ['{http://www.w3.org/XML/1998/namespace}lang', 'ID'], {'theZ':'TheZ', 'theT':'TheT','theC':'TheC'}, {"LogicalChannelRef":"ChannelRef"});


    def test_detector_type(self):
        """
        Checks that the Detector types have been correctly transformed.
        """
        fromElements = self.getAllElements(self.old_root, self.OLD_OME_NS,
                                           ['Detector'])
        toElements = self.getAllElements(self.new_root, self.NEW_OME_NS,
                                         ['Detector'])
        self.assertEqual(len(fromElements), len(toElements))
        print "Element count: %d" % len(toElements)
        for element in toElements:
            print dump(element)

    """
    Follow a collection of tests for transformation related to ROI elements.
    """

    def test_shape_transformation(self):
        """
        Checks that the Detector types have been correctly transformed.
        """

if __name__ == '__main__':
    unittest.main()
"""
    try:
        options, args = getopt(sys.argv[1:], "")
    except GetoptError, (msg, opt):
        usage(msg)

    for option, argument in options:
        pass

    xslt_filename = "2008-09.xsl"
    xslt = open(xslt_filename)
    in_filename = "tmp/sample-lsm-nobindata.ome"
    in_file = open(in_filename)
    try:
        print "Running XSLT %s on %s..." % (xslt_filename, in_filename)
        run_stylesheet(xslt, in_file, None)
    finally:
        xslt.close()
        in_file.close()
"""
